package scau.hotel.hotel_service.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import scau.hotel.hotel_model.controller.RespBean;
import scau.hotel.hotel_model.controller.RespBeanEnum;
import scau.hotel.hotel_service.entity.Payment;
import scau.hotel.hotel_service.entity.RoomTypeDiscount;
import scau.hotel.hotel_service.mapper.*;
import scau.hotel.hotel_service.service.PaymentService;
import scau.hotel.hotel_service.util.DateUtil;
import scau.hotel.hotel_service.vo.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * (Payment)表服务实现类
 *
 * @author makejava
 * @since 2022-03-28 20:19:16
 */
@Service("paymentService")
public class PaymentServiceImpl implements PaymentService {
    @Resource
    private PaymentMapper paymentMapper;
    @Resource
    private RoomMapper roomMapper;
    @Resource
    private RoomTypeMapper roomTypeMapper;
    @Resource
    private PricingRuleMapper pricingRuleMapper;
    @Resource
    private RoomTypeDiscountMapper roomTypeDiscountMapper;
    @Resource
    private CheckinInforMapper checkinInforMapper;
    @Autowired
    private DateUtil dateUtil;

    /**
     * 通过ID查询单条数据
     *
     * @param paymentId 主键
     * @return 实例对象
     */
    @Override
    public Payment queryById(Integer paymentId) {
        return this.paymentMapper.queryById(paymentId);
    }

    /**
     * 分页查询
     *
     * @param payment 筛选条件
     * @return 查询结果
     */
    @Override
    public List<Payment> queryAll(Payment payment) {
        return this.paymentMapper.queryAll(payment);
    }

    /**
     * 查询某一天的支付表数据
     *
     * @param getPriceVo 筛选条件
     * @return 查询结果
     */
    @Override
    public List<LineEChartsVo> querySomeDayInCome(GetPriceVo getPriceVo) {
        DateUtil dateUtil = new DateUtil();//时间计算工具类
        List<LineEChartsVo> lineEChartsVos = new ArrayList<>();//返回结果
        List<Payment> paymentList = new ArrayList<>();//每一天的支付表数据
        Date startTime = getPriceVo.getCheckinDate();//起始时间
        Date middleTime;//中间时间变量
        Date endTime = getPriceVo.getCheckoutDate();//末期时间
        Calendar calendar = new GregorianCalendar();
        for (int i = 0; i <= dateUtil.differDay(startTime,endTime); i++) {
            LineEChartsVo lineEChartsVo = new LineEChartsVo();//每天营业额存储对象
            BigDecimal totalInCome = new BigDecimal("0.0");//每一天的总收入
            calendar.setTime(startTime);
            calendar.add(calendar.DATE,i); //把日期往后增加i天
            middleTime = calendar.getTime(); //获取遍历时间
            paymentList = querySomeDayPayment(middleTime);
            for (Payment payment : paymentList) {
                totalInCome = totalInCome.add(payment.getAmount()); //计算当天时间总收入
            }
            lineEChartsVo.setDate(middleTime);
            lineEChartsVo.setInCome(totalInCome);
            lineEChartsVos.add(lineEChartsVo);
        }
        return lineEChartsVos;
    }

    /**
     * 查询某一天的支付表数据
     *
     * @param date 筛选条件
     * @return 查询结果
     */
    public List<Payment> querySomeDayPayment(Date date) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String s1 = sdf.format(date); // 把带时分秒的 date1 转为 yyyy-MM-dd 格式的字符串
        Date d1 = new Date();
        try {
            d1 = sdf.parse(s1); // 把上面的字符串解析为日期类型
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return this.paymentMapper.querySomeDayPayment(d1);
    }

    /**
     * 分页查询
     *
     * @param payment 筛选条件
     * @param pageRequest      分页对象
     * @return 查询结果
     */
    @Override
    public Page<Payment> queryByPage(Payment payment, PageRequest pageRequest) {
        long total = this.paymentMapper.count(payment);
        return new PageImpl<>(this.paymentMapper.queryAllByLimit(payment, pageRequest), pageRequest, total);
    }

    /**
     * 新增数据
     *
     * @param payment 实例对象
     * @return 实例对象
     */
    @Override
    public RespBean insert(Payment payment) {
        this.paymentMapper.insert(payment);
        return RespBean.success();
    }

    /**
     * 修改数据
     *
     * @param payment 实例对象
     * @return 实例对象
     */
    @Override
    public RespBean update(Payment payment) {
        Integer checkinInfoId = this.paymentMapper.queryById(payment.getPaymentId()).getCheckinInforId();
        if(Objects.equals(this.paymentMapper.queryCashPledge(checkinInfoId).getStatus(), "已入账")){
            return RespBean.error(RespBeanEnum.CHECKIN_INFO_STATUS_ERROR);
        }else {
            this.paymentMapper.update(payment);
            return RespBean.success();
        }
    }

    /**
     * 通过主键删除数据
     *
     * @param paymentId 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Integer paymentId) {
        return this.paymentMapper.deleteById(paymentId) > 0;
    }


    /**
     * 根据折扣规则计算最后价格
     *
     * @param getPriceVo
     * @return
     */
    @Override
    public RespBean getFinalPrice(GetPriceVo getPriceVo) {
        //根据房间id获取房型id
        Integer roomTypeId = this.roomMapper.queryById(getPriceVo.getRoomId()).getRoomTypeId();
        //获取入住时间
        Date checkinDate = getPriceVo.getCheckinDate();
        //获取预计退房时间
        Date checkoutDate = getPriceVo.getCheckoutDate();
        //计算价格
        return this.getPrice(checkinDate,checkoutDate,roomTypeId);
    }

    /**
     * 根据折扣规则计算最后价格
     *
     * @param
     * @return
     */
    @Override
    public RespBean getPrice(Date checkinDate, Date checkoutDate, Integer roomTypeId) {
        //判断入住时间是否在退房时间前
        if (checkinDate.before(checkoutDate)) {
            //根据房型查询基础价格
            BigDecimal roomTypePrice = this.roomTypeMapper.queryById(roomTypeId).getRoomTypePrice();
            //根据房型id搜索该房型的折扣
            List<RoomTypeDiscount> roomTypeDiscountList = this.roomTypeDiscountMapper.queryDiscountByRoomTypeId(roomTypeId);

            /*根据折扣规则处理价格*/
            //设置支付表的的价格为基础价格
            BigDecimal roomPrice = roomTypePrice;

            //计算入住天数,后者减前者
            Integer days = this.dateUtil.differDay(checkinDate, checkoutDate);

            //循环获取数据库中折扣日期，判断是否符合折扣日期
            for (int i = 0; i < roomTypeDiscountList.size(); i++) {

                //获取折扣开始时间
                Date discount_start = this.pricingRuleMapper.queryById(roomTypeDiscountList.get(i).getPricingRuleId()).getStartDate();
                //获取折扣结束时间
                Date discount_end = this.pricingRuleMapper.queryById(roomTypeDiscountList.get(i).getPricingRuleId()).getEndingDate();

                //该折扣有时间区间
                if (discount_start != null && discount_end != null) {
                    //调用相应的折扣
                    BigDecimal discount = this.pricingRuleMapper.queryById(roomTypeDiscountList.get(i).getPricingRuleId()).getDiscount();

                    /* 计算入住期间是否符合该折扣区间 */
                    //入住时间在折扣区间内
                    if (this.dateUtil.differDay(discount_start, checkinDate) >= 0
                            && this.dateUtil.differDay(checkinDate, discount_end) >= 0) {
                        //情况一：入住时间在折扣区间内，退房时间也在折扣区间内，房价全款折扣
                        if (this.dateUtil.differDay(checkoutDate, discount_end) >= 0) {
                            //基础价格乘折扣以及天数后的价格
//                        roomPrice = roomTypePrice * discount * days;
                            roomPrice = roomTypePrice.multiply(discount).multiply(BigDecimal.valueOf(days));
                            break;
                        }
                        //情况二：入住时间在折扣区间内，退房时间不在折扣区间内，房价部分折扣
                        else {
                            //day1等于折扣结束时间减去入住时间，该时间段有折扣
                            Integer day1 = this.dateUtil.differDay(checkinDate, discount_end);
                            //day2等于退房时间减去折扣结束时间，该时间段无折扣
                            Integer day2 = this.dateUtil.differDay(discount_end, checkoutDate);
                            //计算房价
//                        roomPrice = roomTypePrice * discount * day1 + roomTypePrice * day2;
                            roomPrice = roomTypePrice.multiply(discount).multiply(BigDecimal.valueOf(day1)).add(roomTypePrice.multiply(BigDecimal.valueOf(day2)));
                            break;
                        }
                    }
                    //入住时间在折扣开始时间前
                    else if (this.dateUtil.differDay(checkinDate, discount_start) > 0) {
                        //情况三：入住时间在折扣开始时间前，退房时间在折扣区间内，房价部分折扣
                        if (this.dateUtil.differDay(checkoutDate, discount_end) >= 0
                                && this.dateUtil.differDay(discount_start, checkoutDate) > 0) {
                            //day3等于折扣开始时间减去入住时间，该时间段无折扣
                            Integer day3 = this.dateUtil.differDay(checkinDate, discount_start);
                            //day4等于退房时间减去折扣开始时间，该时间段有折扣
                            Integer day4 = this.dateUtil.differDay(discount_start, checkoutDate);
                            //计算房价
//                        roomPrice = roomTypePrice * discount * day4 + roomTypePrice * day3;
                            roomPrice = roomTypePrice.multiply(discount).multiply(BigDecimal.valueOf(day4)).add(roomTypePrice.multiply(BigDecimal.valueOf(day3)));
                            break;
                        }
                        //情况四：入住时间在折扣开始时间前，退房时间在折扣结束时间后，房价部分折扣
                        else if (this.dateUtil.differDay(discount_end, checkoutDate) > 0) {
                            //day5等于折扣结束时间减去折扣开始时间，该时间段有折扣
                            Integer day5 = this.dateUtil.differDay(discount_start, discount_end);
                            //day6等于退房时间减去入住时间，该时间段为入住总天数
                            Integer day6 = days;
                            //计算房价
//                        roomPrice = roomTypePrice * discount * day5 + roomTypePrice * (day6-day5);
                            roomPrice = roomTypePrice.multiply(discount).multiply(BigDecimal.valueOf(day5)).add(roomTypePrice.multiply(BigDecimal.valueOf((day6 - day5))));
                            break;
                        }
                    }
                }
            }
            //判断如果房价依旧等于基础价格，则入住期间不符合任何折扣区间，房费无折扣，按基础价格计算
            if (Objects.equals(roomPrice, roomTypePrice)) {
//            roomPrice = roomTypePrice * days;
                roomPrice = roomTypePrice.multiply(BigDecimal.valueOf(days));
            }
            return RespBean.success(roomPrice);
        }else{
            return RespBean.error(RespBeanEnum.BIND_ERROR,"日期有误！");
        }
    }

}
